Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.ComponentModel
Imports Raccoom.Windows.Forms
Imports Cryptor

' simple wrapper class for Unzipping by Philip
Public Class RenameUtils

  Public Provider As TreeViewFolderBrowserDataProviderShell32
  Private _rootFolders As StringCollection
  Dim _dCourses As DictValStrings
  Dim _encdec As New EncryptionWorker

  Public ReadOnly Property EncDec() As EncryptionWorker
    Get
      Return _encdec
    End Get
  End Property

  Public Property RootFolders() As StringCollection
    Get
      Return _rootFolders
    End Get
    Set(ByVal value As StringCollection)
      _rootFolders = value
    End Set
  End Property

  Private _sourceDir As String
  Public Property SourceDir() As String
    Get
      Return _sourceDir
    End Get
    Set(ByVal value As String)
      _sourceDir = value
    End Set
  End Property

  Private _targetDir As String
  Public Property TargetDir() As String
    Get
      Return _targetDir
    End Get
    Set(ByVal value As String)
      _targetDir = value
    End Set
  End Property

  Private _testMode As Boolean
  Public Property TestMode() As Boolean
    Get
      Return _testMode
    End Get
    Set(ByVal value As Boolean)
      _testMode = value
    End Set
  End Property


  Private _Encrypt As Boolean
  Public Property Encrypt() As Boolean
    Get
      Return _Encrypt
    End Get
    Set(ByVal value As Boolean)
      _Encrypt = value
    End Set
  End Property


  Private _decrypt As Boolean
  Public Property Decrypt() As Boolean
    Get
      Return _decrypt
    End Get
    Set(ByVal value As Boolean)
      _decrypt = value
    End Set
  End Property

  Private _fileMask As String
  Private _fileMaskAr As String()
  Public Property FileMask() As String
    Get
      Return _fileMask
    End Get
    Set(ByVal value As String)
      _fileMask = value
      _fileMaskAr = value.Split(","c)
    End Set
  End Property

  Private _treeView As TreeViewFolderBrowser
  Public Property TreeViewFolderBrowser() As TreeViewFolderBrowser
    Get
      Return _treeView
    End Get
    Set(ByVal value As TreeViewFolderBrowser)
      _treeView = value
    End Set
  End Property

  Private _numDigits As Integer
  Public Property NumDigits() As Integer
    Get
      Return _numDigits
    End Get
    Set(ByVal value As Integer)
      _numDigits = value
    End Set
  End Property


  Private _renameFolders As Boolean
  Public Property RenameFolders() As Boolean
    Get
      Return _renameFolders
    End Get
    Set(ByVal value As Boolean)
      _renameFolders = value
    End Set
  End Property

  Private _renameFolderType As Integer
  Public Property RenameFolderType() As Integer
    Get
      Return _renameFolderType
    End Get
    Set(ByVal value As Integer)
      _renameFolderType = value
    End Set
  End Property

  Private _startNumber As Integer
  Public Property StartNumber() As Integer
    Get
      Return _startNumber
    End Get
    Set(ByVal value As Integer)
      _startNumber = value
    End Set
  End Property

  Private _numChecked As Integer
  Public Property NumChecked() As Integer
    Get
      Return _numChecked
    End Get
    Set(ByVal value As Integer)
      _numChecked = value
    End Set
  End Property


  Private _worker As BackgroundWorker
  Public Property Worker() As BackgroundWorker
    Get
      Return _worker
    End Get
    Set(ByVal value As BackgroundWorker)
      _worker = value
    End Set
  End Property

  Private _dweArgs As DoWorkEventArgs
  Public Property DweArgs() As DoWorkEventArgs
    Get
      Return _dweArgs
    End Get
    Set(ByVal value As DoWorkEventArgs)
      _dweArgs = value
    End Set
  End Property
  Dim _currWorkType As Integer
  Public ReadOnly Property CurrWorkType() As Integer
    Get
      Return _currWorkType
    End Get
  End Property

  Sub DoWork(ByVal workType As Integer)
    _currWorkType = workType
    Select Case workType
      Case 0
        FindAllFilesOfMaskInDir()
      Case 1
        RenameAllFilesOfMask()
    End Select
  End Sub
  Sub RenameAllFilesOfMask()
    Dim d1, d2 As IO.DirectoryInfo
    _iFile = Me.StartNumber
    If _rootFolders.Count > 0 Then
      For Each root As String In _rootFolders
        d1 = New IO.DirectoryInfo(root)
        d2 = New IO.DirectoryInfo(root)
        Dim n As TreeNodePath = Me.TreeViewFolderBrowser.GetRootNode(root)
        renameAllFilesOfMaskRecursive(d1, d2, n)
      Next
    Else
      d1 = New IO.DirectoryInfo(_sourceDir)
      d2 = New IO.DirectoryInfo(_targetDir)
      renameAllFilesOfMaskRecursive(d1, d2, Nothing)
    End If
  End Sub

  Private Function GetFormatString(ByVal iNum As Integer) As String
    Dim formatString As String
    formatString = "{" & iNum & ":" & New String("0"c, Me.NumDigits) & "}"
    Return formatString
  End Function
  Public Class RenameProgressArgs
    Public Node As TreeNodePath
    Public NewName As String
    Sub New(ByVal n As TreeNodePath, ByVal newn As String)
      Node = n
      NewName = newn
    End Sub
  End Class

  Dim _iFile As Integer
  Public CurrNewName As String
  Private Sub renameAllFilesOfMaskRecursive(ByVal d1 As IO.DirectoryInfo, ByVal d2 As IO.DirectoryInfo, _
  ByVal n1 As TreeNodePath)
    Dim fi As IO.FileInfo, subd1, subd2 As IO.DirectoryInfo
    Dim iStart, iEnd As Integer
    Dim subn1, fni As TreeNodePath
    Dim formatString, newPath, origName, origExt, courseDesc As String
    Dim pctProg As Integer

    iStart = _iFile
    For Each subd1 In d1.GetDirectories()
      subn1 = n1.GetChildNode(subd1.Name, False)
      subd2 = d2.CreateSubdirectory(subd1.Name)
      If subn1 IsNot Nothing AndAlso _
       (subn1.Checked OrElse subn1.HasChildNodesChecked()) Then
        renameAllFilesOfMaskRecursive(subd1, subd2, subn1)
      End If
    Next

    If n1.Checked OrElse n1.HasChildNodesChecked() Then
      For Each fi In d1.GetFiles()
        If _worker IsNot Nothing AndAlso _worker.CancellationPending Then
          _dweArgs.Cancel = True
          Exit Sub
        End If
        If isFileOfFileMask(fi) Then
          fni = n1.GetChildNode(fi.Name, True)
          If fni IsNot Nothing AndAlso fni.Checked Then
            'increase decompress counter
            pctProg = ((_iFile - Me.StartNumber) * 100) / FileList.Count
            If pctProg > 100 Then pctProg = 100
            ' extract zip or sleep for a while
            If Not _testMode Then
              Try
                origName = IO.Path.GetFileNameWithoutExtension(fi.Name)
                origExt = fi.Extension
                formatString = "(" & GetFormatString(0) & ") {1}{2}"
                CurrNewName = String.Format(formatString, _iFile, origName, origExt)
                If Me.Encrypt Then : EncryptFile(fi, d2)
                ElseIf Me.Decrypt Then : DecryptFile(fi, d2)
                  'If String.Compare(d1.FullName, d2.FullName, True) <> 0 Then
                  '  fi.CopyTo(IO.Path.Combine(d2.FullName, CurrNewName), True)
                  'End If
                Else ' not encrypt/decrypt just rename
                  ' append course name if mct file
                  If d1.Name.ToLower().Contains("mct") Then
                    Dim v As Integer = Val(fi.Name)
                    If v > 0 AndAlso _dCourses.ContainsKey(v) Then
                      courseDesc = _dCourses(v)
                      If Not origName.Contains(courseDesc) Then
                        CurrNewName = origName & " " & courseDesc & origExt
                      End If
                    End If
                  End If ' mct
                  ' do rename file here
                  If String.Compare(fi.Name, CurrNewName, True) <> 0 Then
                    newPath = IO.Path.Combine(d2.FullName, CurrNewName)
                    If Not IO.File.Exists(newPath) Then fi.MoveTo(newPath)
                  End If
                End If
                'Catch ex As Exception
                '  MsgBox(ex.Message)
              Finally
              End Try
            Else : System.Threading.Thread.Sleep(50)
            End If ' test mode
            Dim eFileProg As New RenameProgressArgs(fni, CurrNewName)
            If Worker IsNot Nothing Then Worker.ReportProgress(pctProg, eFileProg)
            _iFile += 1
          End If
        End If
      Next
      iEnd = _iFile
      ' If Not Me.Encrypt AndAlso Not Me.Decrypt Then
      RenameFolder(d1, d2, n1, iStart, iEnd, pctProg)
      'End If
    End If
  End Sub
  Sub EncryptFile(ByVal fi As IO.FileInfo, ByVal d2 As IO.DirectoryInfo)
    'Dim encName As String : Dim encBytes As Byte()
    'Dim fsEnc As IO.FileStream = Nothing, sw As IO.BinaryWriter = Nothing
    'Dim formatString As String = GetFormatString(0) & ".enc"
    'CurrNewName = String.Format(formatString, _iFile)
    'Dim newPath As String = IO.Path.Combine(d2.FullName, CurrNewName)
    'encName = DataProtection.ProtectData(fi.Name, "FileName")
    'encBytes = DataProtection.ProtectData(IO.File.ReadAllBytes(fi.FullName), "FileData")
    'Try
    '  fsEnc = New IO.FileStream(newPath, IO.FileMode.OpenOrCreate)
    '  sw = New IO.BinaryWriter(fsEnc)
    '  sw.Write(encName) : sw.Write(encBytes.Length) : sw.Write(encBytes)
    'Catch ex As Exception
    '  Debug.WriteLine("Exception while encrypting file " & fi.FullName & ": " & ex.Message)
    'Finally
    '  If sw IsNot Nothing Then sw.Close()
    '  If fsEnc IsNot Nothing Then fsEnc.Close()
    'End Try
    'Try
    '  If IO.File.Exists(newPath) Then fi.Delete()
    'Catch ex As Exception
    'End Try
    _encdec.SetData(fi.FullName, True, True)
    CurrNewName = IO.Path.GetFileName(_encdec.OutputFile)
    _encdec.TransformFile()
  End Sub
  Sub DecryptFile(ByVal fi As IO.FileInfo, ByVal d2 As IO.DirectoryInfo)
    'Dim fsEnc As IO.FileStream = Nothing, sr As IO.BinaryReader = Nothing
    'Dim fsDecr As IO.FileStream = Nothing, sw As IO.BinaryWriter = Nothing
    'Dim decrBytes As Byte(), newPath As String
    '' encrypted files end with .enc
    'If Not fi.Name.EndsWith(".enc") Then Exit Sub
    'Try
    '  fsEnc = New IO.FileStream(fi.FullName, IO.FileMode.Open)
    '  sr = New IO.BinaryReader(fsEnc)
    '  CurrNewName = DataProtection.UnprotectData(sr.ReadString())
    '  newpath = IO.Path.Combine(d2.FullName, CurrNewName)
    '  Dim datalen As Integer = sr.ReadInt32()
    '  decrBytes = DataProtection.UnprotectData(sr.ReadBytes(datalen))
    '  IO.File.WriteAllBytes(newPath, decrBytes)
    'Catch ex As Exception
    '  Debug.WriteLine("Exception while encrypting file " & fi.FullName & ": " & ex.Message)
    'Finally
    '  If sr IsNot Nothing Then sr.Close()
    '  If fsEnc IsNot Nothing Then fsEnc.Close()
    'End Try
    'Try
    '  If IO.File.Exists(newPath) Then fi.Delete()
    'Catch ex As Exception
    'End Try
    _encdec.SetData(fi.FullName, False, True)
    _encdec.TransformFile()
    CurrNewName = IO.Path.GetFileName(_encdec.OutputFile)
  End Sub
  Public Sub RenameFolder(ByVal d1 As IO.DirectoryInfo, ByVal d2 As IO.DirectoryInfo, _
   ByVal n1 As TreeNodePath, ByVal iStart As Integer, ByVal iEnd As Integer, ByVal pctProg As Integer)
    Dim sRange, sFS, newPath, courseDesc As String
    CurrNewName = ""
    If Me.RenameFolders AndAlso n1.Checked AndAlso iEnd > iStart Then
      sFS = String.Format("{0},{1}", GetFormatString(0), GetFormatString(1))
      sRange = String.Format("[" & sFS & "]", iStart, iEnd - 1)
      If Me.RenameFolderType = 0 Then
        CurrNewName = sRange & " " & d1.Name
      Else
        CurrNewName = d1.Name & " " & sRange
      End If
    End If
    ' special case ---
    If d1.Parent IsNot Nothing AndAlso d1.Parent.Name.ToLower().Contains("mct") Then
      Dim v As Integer = Val(d1.Name)
      If v > 0 AndAlso _dCourses.ContainsKey(v) Then
        courseDesc = _dCourses(v)
        If Not d1.Name.Contains(courseDesc) Then
          CurrNewName = d1.Name & " " & courseDesc
        End If
      End If
    End If
    If CurrNewName.Length > 0 Then
      newPath = IO.Path.Combine(d2.Parent.FullName, CurrNewName)
      If Not IO.Directory.Exists(newPath) Then d2.MoveTo(newPath)
      Dim eFolderProg As New RenameProgressArgs(n1, CurrNewName)
      If Worker IsNot Nothing Then Worker.ReportProgress(pctProg, eFolderProg)
    End If
  End Sub
  ' delete alll zips in directory
  Sub DeleteAllInDir()
    Dim d1 As IO.DirectoryInfo
    d1 = New IO.DirectoryInfo(_sourceDir)
    delAllRec(d1)
  End Sub
  Private Sub delAllRec(ByVal d1 As IO.DirectoryInfo)
    Dim fi As IO.FileInfo, subd1 As IO.DirectoryInfo
    For Each fi In d1.GetFiles()
      If isFileOfFileMask(fi) Then
        If Not _testMode Then fi.Delete()
      End If
    Next
    For Each subd1 In d1.GetDirectories()
      delAllRec(subd1)
    Next
  End Sub
  Private Function isFileOfFileMask(ByVal fi As IO.FileInfo) As Boolean
    'For Each mask As String In _fileMaskAr
    '  If String.Compare(fi.Extension, "." & mask, True) = 0 Then
    '    Return True
    '  End If
    'Next
    'Return False
    Return TreeViewFolderBrowserDataProviderShell32.IsFileOfFileMask( _
     fi.FullName, Provider.FileMask, Provider.MaskInclude)
  End Function
  ' find all zips in directory
  Dim _fileList As New List(Of String)
  Dim _folderList As New List(Of String)
  Dim _iFolders As Integer = 0
  Public ReadOnly Property FileList() As List(Of String)
    Get
      Return _fileList
    End Get
  End Property

  Public ReadOnly Property NumFolders() As Integer
    Get
      If _iFolders < 0 Then _iFolders = 0
      Return _iFolders
    End Get
  End Property

  Sub FindAllFilesOfMaskInDir()
    Dim d1 As IO.DirectoryInfo
    _fileList.Clear()
    _folderList.Clear()
    _iFolders = -1
    If Me.RootFolders.Count = 0 Then
      d1 = New IO.DirectoryInfo(_sourceDir)
      findAllFilesOfMasksRec(d1, Nothing)
    Else
      ' use temporary array because the original will be modified
      Dim tempRootFolders As New StringCollection()
      Dim tempArray(RootFolders.Count - 1) As String
      RootFolders.CopyTo(tempArray, 0)
      tempRootFolders.AddRange(tempArray)
      For Each root As String In tempRootFolders
        d1 = New IO.DirectoryInfo(root)
        Dim n As TreeNodePath = Me.TreeViewFolderBrowser.GetRootNode(root)
        findAllFilesOfMasksRec(d1, n)
      Next
    End If
  End Sub
  Private Sub findAllFilesOfMasksRec(ByVal d1 As IO.DirectoryInfo, ByVal n1 As TreeNodePath)
    Dim fi As IO.FileInfo, subd1 As IO.DirectoryInfo
    Dim subn1, fni As TreeNodePath
    Try
      If n1.Checked OrElse n1.HasChildNodesChecked() Then
        If Not _folderList.Contains(d1.FullName) Then
          _iFolders += 1
          _folderList.Add(d1.FullName)
        End If
        For Each fi In d1.GetFiles()
          If isFileOfFileMask(fi) Then
            fni = n1.GetChildNode(fi.Name, True)
            If fni IsNot Nothing AndAlso fni.Checked Then
              If Not _fileList.Contains(fi.FullName) Then
                _fileList.Add(fi.FullName)
                Dim pctRound As Integer = _fileList.Count * 100 / Me.NumChecked
                If pctRound > 100 Then pctRound = 100
                CurrNewName = fi.Name
                Dim eFileProg As New RenameProgressArgs(fni, CurrNewName)
                If Worker IsNot Nothing Then Worker.ReportProgress(pctRound, eFileProg)
              End If
            End If
          End If
        Next
      End If
      For Each subd1 In d1.GetDirectories()
        subn1 = n1.GetChildNode(subd1.Name, False)
        If subn1 IsNot Nothing AndAlso _
         (subn1.Checked OrElse subn1.HasChildNodesChecked()) Then
          findAllFilesOfMasksRec(subd1, subn1)
        End If
      Next
    Catch ex As Exception
      If TypeOf ex Is System.IO.IOException Then
        If RootFolders.Contains(n1.Path) Then RootFolders.Remove(n1.Path)
      End If
      Exit Sub
    End Try
  End Sub

  Public Sub New()
    _rootFolders = New StringCollection
    _dCourses = New DictValStrings(IO.Path.Combine(Application.StartupPath, "mct_courses.txt"))
  End Sub
End Class

'MFC-like wait cursor!
Class WaitCursor
  Implements IDisposable

  Private disposedValue As Boolean = False    ' To detect redundant calls

  ' IDisposable
  Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposedValue Then
      If disposing Then
        ' TODO: free unmanaged resources when explicitly called
      End If

      ' TODO: free shared unmanaged resources
      _frm.Cursor = Cursors.Default
    End If
    Me.disposedValue = True
  End Sub

#Region " IDisposable Support "
  ' This code added by Visual Basic to correctly implement the disposable pattern.
  Public Sub Dispose() Implements IDisposable.Dispose
    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region

  Dim _frm As Form
  Public Sub New(ByVal frm As Form)
    _frm = frm
    _frm.Cursor = Cursors.WaitCursor
  End Sub
End Class